home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir39 / 550reset.zip / 550RESET.C next >
C/C++ Source or Header  |  1994-08-06  |  4KB  |  145 lines

  1. /* 
  2.     This program clears the 16550A's FIFO to prevent system hangs
  3.     when "Super I/O" cards with SMC665 or SMC666 chips are used with
  4.     communications programs that enable the 16550A UART. Just run this
  5.     program before you run your favorite communications program and you
  6.     should *not* experience further system hangs.  NOTE: If you have an 
  7.     external device connect it and turn it on BEFORE you run this program.  
  8.  
  9.     The specific problem is that if you output a 0x7 to the FIFO control
  10.     register of these chips while there is data in the FIFO the chip will
  11.     go into a state where the Receive Ready flag (bit 0 in the LSR)
  12.     remains high NO MATTER HOW MANY TIMES YOU READ THE RECEIVER BUFFER
  13.     REGISTER.  If your communication program is unfortunate enough to enable
  14.     interrupts while the UART is in this condition your system will lockup,
  15.     and require a hardware reset or power cycle to restore operation.  
  16.     Needless to say this is inconvenient!
  17.  
  18.     I discovered this problem when I upgraded my "SUPER I/O card" to a
  19.     "SIDE jr L" vlb card.  While the features are great I immediately ran into
  20.     problem with EVERY program I have that uses serial I/O.  I found that I
  21.     could only execute Windows programs that used serial I/O once, the 
  22.     whole system locked up the second time I ran the program.  This occurred
  23.     with several different Windows programs.  Searching the Microsoft Knowledge
  24.     base yielded the answer... an updated SERIAL.386 driver (search for
  25.     WG1001 for the new driver).  Unfortunately the new Windows driver did 
  26.     nothing for DOS programs I use regularly such as Qmodem and Telix, that is
  27.     why I wrote this program.  The Microsoft writeup provided enough 
  28.     information on the problem for this program to be written.  
  29.  
  30.  
  31.     Comments are welcome:
  32.  
  33.         Skip Hansen WB6YMH.
  34.         internet: wb6ymh@amsat.org
  35.         BBS: (310) 541-2503
  36.         Packet: WB6YMH@WB6YMH.#SOCAL.CA.USA
  37.  
  38.     If you find this program of value I am pleased, send no cash!
  39. */
  40.  
  41. enum UART_TYPE{
  42.     UNKNOWN,
  43.     UART_TYPE_8250,
  44.     UART_TYPE_16450,
  45.     UART_TYPE_16550,
  46.     UART_TYPE_16550A
  47. };
  48.  
  49.  
  50. #define    RBR    0
  51. #define    THR    0
  52. #define    IER    1
  53. #define    FCR    2
  54. #define    IIR    2
  55. #define    LCR    3
  56. #define    MCR    4
  57. #define    LSR    5
  58. #define    MSR    6
  59. #define    SCR    7
  60.  
  61. #define    FIFO_ENABLED_6    0x40
  62. #define    FIFO_ENABLED_7    0x80
  63.  
  64. #define    FIFO_ENABLE    1
  65.  
  66.  
  67. void reset(int port)
  68. {
  69.     int i;
  70.  
  71.     outp(port+FCR,1);    // enable FIFO
  72.     if( (inp(port+IIR) & 0xc0) != 0xc0){
  73.         printf("Port 0x%0x does not appear to be an 16550 UART.\n",port);
  74.         return;
  75.     }
  76.     outp(port+FCR,0);    // disable FIFO
  77.     i = 0;
  78.     while(i++ < 16 && (inp(port+LSR) & 1)){
  79.         inp(port+RBR);
  80.     }
  81.     if(i == 16){
  82.         printf("Unable to clear FIFO on UART at port 0x%0x after 16 reads!\n",port);
  83.     }
  84.     return;
  85. }
  86.  
  87. enum UART_TYPE id_uart(int port)
  88. {
  89.     char temp;
  90.  
  91.     // first check the scratch register
  92.  
  93.     temp = inp(port+SCR);
  94.     outp(port+SCR,0x55);
  95.     if(inp(port+SCR) != 0x55){
  96.         printf("Uart at port 0x%0x is a 8250.\n",port);
  97.         return UART_TYPE_8250;
  98.     }
  99.  
  100.     outp(port+SCR,0xaa);
  101.     if(inp(port+SCR) != 0xaa){
  102.         printf("UART at port 0x%0x is a 8250.\n",port);
  103.         return UART_TYPE_8250;
  104.     }
  105.  
  106.     outp(port+SCR,temp);        // restore original value (an case anyone cares!)
  107.  
  108.     // we have at least a 16450.
  109.  
  110.     outp(port+FCR,0);            // disable the FIFO
  111.  
  112.     if((inp(port+IIR) & FIFO_ENABLED_6) != 0 || (inp(port+IIR) & FIFO_ENABLED_6) != 0){
  113.         printf("Unknown UART at port 0x%0x.\n",port);
  114.         printf("(Bits 6 and 7 of the IIR are not ZERO with the FIFO disabled.\n");
  115.         return UNKNOWN;
  116.     }
  117.  
  118.     outp(port+FCR,FIFO_ENABLE);            // enable the FIFO
  119.  
  120.     if((inp(port+IIR) & FIFO_ENABLED_6) != FIFO_ENABLED_6) {
  121.         printf("UART at port 0x%0x is a 16450.\n",port);
  122.         return UART_TYPE_16450;
  123.     }
  124.     
  125.     if((inp(port+IIR) & FIFO_ENABLED_7) != FIFO_ENABLED_7) {
  126.         printf("UART at port 0x%0x is a 16550.\n",port);
  127.         printf("(NOT a 16550A, do not use the FIFO function, it's BROKEN!)\n");
  128.         return UART_TYPE_16550;
  129.     }
  130.  
  131.     printf("UART at port 0x%0x is a 16550A.\n",port);
  132.     return UART_TYPE_16550A;
  133.  
  134. }
  135.  
  136. main()
  137. {
  138.     if(id_uart(0x2f8) == UART_TYPE_16550A){
  139.         reset(0x2f8);
  140.     }
  141.     if(id_uart(0x3f8) == UART_TYPE_16550A){
  142.         reset(0x3f8);
  143.     }
  144. }
  145.